package com.by.basicweb.validator;


import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

import static com.by.toolkit.utils.ExceptionUtil.getStackTrace;

@Slf4j
public class DateRangeValidator implements ConstraintValidator<DateRange, Object> {


    private String startDateFieldName;
    private String endDateFieldName;
    private Integer timeDifference;
    private ChronoUnit chronoUnit;

    @Override
    public void initialize(DateRange constraintAnnotation) {
        this.startDateFieldName = constraintAnnotation.startDate();
        this.endDateFieldName = constraintAnnotation.endDate();
        this.timeDifference = constraintAnnotation.timeDifference();
        this.chronoUnit = constraintAnnotation.chronoUnit();
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) {
        try {
            Field startDateField = value.getClass().getDeclaredField(startDateFieldName);
            Field endDateField = value.getClass().getDeclaredField(endDateFieldName);
            startDateField.setAccessible(true);
            endDateField.setAccessible(true);
            log.info("[DateRangeValidator][isValid] {},{}",startDateField.getName(),endDateField.getName());
            Object startDateDateTimeObj = startDateField.get(value);
            Object endDateDateTimeObj = endDateField.get(value);
            if (ObjectUtil.isAllEmpty(startDateDateTimeObj, endDateDateTimeObj)) {
                return true;
            }

            if (startDateDateTimeObj instanceof LocalDateTime && endDateDateTimeObj instanceof LocalDateTime) {
                LocalDateTime startDate = (LocalDateTime) startDateField.get(value);
                LocalDateTime endDate = (LocalDateTime) endDateField.get(value);
                log.info("[DateRangeValidator][isValid] startDate:{} endDate:{}", startDate, endDate);
                if (startDate == null || endDate == null) {
                    return true; // Consider null values as valid. You can change this logic as needed.
                }
                long daysBetween = chronoUnit.between(startDate, endDate);
                return daysBetween <= timeDifference;

            } else if (startDateDateTimeObj instanceof LocalDate && endDateDateTimeObj instanceof LocalDate) {

                LocalDateTime startDateTime = (LocalDateTime) startDateField.get(value);
                LocalDateTime endDateTime = (LocalDateTime) endDateField.get(value);
                log.info("[DateRangeValidator][isValid] startDateTime:{} endDateTime:{}", startDateTime, endDateTime);
                if (startDateTime == null || endDateTime == null) {
                    return true; // Consider null values as valid. You can change this logic as needed.
                }

                long daysBetween = chronoUnit.between(startDateTime, endDateTime);
                return daysBetween <= timeDifference;
            } else if (startDateDateTimeObj instanceof Long && endDateDateTimeObj instanceof Long) {

                Long startDateLong = (Long) startDateField.get(value);
                Long endDateLong = (Long) endDateField.get(value);
                log.info("[DateRangeValidator][isValid] startDateLong:{} endDateLong:{}", startDateLong, endDateLong);
                if (startDateLong == null || endDateLong == null) {
                    return true; // Consider null values as valid. You can change this logic as needed.
                }
                LocalDateTime startDateTime = LocalDateTimeUtil.of(startDateLong);
                LocalDateTime endDateTime = LocalDateTimeUtil.of(endDateLong);
                long daysBetween = chronoUnit.between(startDateTime, endDateTime);
                return daysBetween <= timeDifference;
            }
        } catch (Exception e) {
            log.info("[DateRangeValidator][isValid] exception:{}", getStackTrace(e));
            return false;
        }
        return true;
    }

}
